/**
 * @class   wosh::SharedTransaction
 * @brief   
 *
 ****************************************************************************
 * @version $Id: SharedTransaction.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_SharedTransaction_H__
 #define __WOSH_Core_SharedTransaction_H__

 #include <woshDefs.h>
 #include <core/Serialization.h>
 #include <core/URI.h>
 #include <map>


namespace wosh {

class SharedMemoryDsm;
class Response;

class Transaction : public virtual ISerializable
 {
	WOSH_SERIALIZABLE_ABSTRACT(wosh::Transaction)

	static const short NO_REPLY = 0;
	static const short ACKED = 1;
	static const short NACKED = 2;

	public:
		enum Transation_STATE {
			STATE_CREATED		= 0x00,
			STATE_FAILED		= 0x01,
			STATE_QUEUED		= 0x02,
			STATE_PRECOMMITTED	= 0x04, ///< 
			STATE_COMMITTED		= 0x08, ///< 
			STATE_ROLLEDBACK	= 0x10  ///< 
		 };

		enum Transation_TYPE {
			TYPE_UNKNOWN		= 0x00,
			TYPE_READ			= 0x01, ///< read operation
			TYPE_WRITE			= 0x02, ///< write operation
			TYPE_DEATH			= 0x03  ///< Death-Certificate
		 };

		enum Transation_SCOPE {
			SCOPE_UNKNOWN		= 0x00,
			SCOPE_AGENTS		= 0x01, ///< operation on agent list, such as a Death-Certificate
			SCOPE_TUPLESPACE	= 0x02, ///< operations on tuple space, such as a total re-synch
			SCOPE_TUPLE			= 0x03  ///< operation on a single tuple, such as R/W
		 };

	public:
		Transaction( SharedMemoryDsm* parent = NULL );
		Transaction( const Transaction& m );
		virtual ~Transaction() { }

/** @name Transaction Interface
 * @{
 ******************************************************************************/
	public:
		virtual WRESULT precommit() = 0;	///< lock resources...
		virtual WRESULT commit() = 0;		///< finalize: do stuff, unlock res
		virtual WRESULT rollback() = 0;		///< rollback precommit and unlock res

		/// loop queued transactions looking for conflicts against this
		/// no matter if transaction were executed or not,
		/// evaluate scope/operation conflicts
		/// return number of conflicts

		// DEVE ESSERE ESEGUITA DOPO COMMIT.. ALTRIMENTI NON PUO FARE ROLLBACK SULLE INVALIDAZIONI ..
		virtual int invalidateConflits( bool nack_them );

	public:
		virtual Transation_TYPE getType() const = 0;
		virtual Transation_SCOPE getScope() const = 0;

//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline int64 getID() const				{ return this->id; }
		inline int64 getCreatorID() const		{ return this->creator_id; }

		inline short getState() const			{ return this->state; }

		inline bool isRead() const				{ return ( getType() == Transaction::TYPE_READ ); }
		inline bool isWrite() const				{ return ( getType() == Transaction::TYPE_WRITE ); }
		inline bool isDeath() const				{ return ( getType() == Transaction::TYPE_DEATH ); }

		inline bool isOnAgents() const			{ return ( getScope() == Transaction::SCOPE_AGENTS ); }
		inline bool isOnTupleSpace() const		{ return ( getScope() == Transaction::SCOPE_TUPLESPACE ); }
		inline bool isOnTuple() const			{ return ( getScope() == Transaction::SCOPE_TUPLE ); }

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setParent( SharedMemoryDsm* dsm_ptr )			{ this->parent = dsm_ptr; }
		void setCreatorID( int64 id )					{ this->creator_id = id; }
		void setTimeStamp( long epoch )					{ this->timestamp = epoch; }

//@}
/** @name ACKs
 * @{
 ******************************************************************************/
	public:
		int countAgentsFlag( short ack_option ) const;

		short getResponseOf( long agent_id ) const;

		inline int getACKsCount() const					{ return countAgentsFlag(Transaction::ACKED); }
		inline int getNACKsCount() const				{ return countAgentsFlag(Transaction::NACKED); }
		inline int getNoReplyCount() const				{ return countAgentsFlag(Transaction::NO_REPLY); }

		inline bool isACKedByAll() const				{ return (getACKsCount() == (int)this->acks.size()); }
		inline bool isNACKedBySomeone() const			{ return (countAgentsFlag(Transaction::NACKED) != 0); }

		const std::map<long, short>& getAcksMap() const	{ return this->acks; }
		std::map<long, short>& getAcksMap()				{ return this->acks; }

		bool isTimedOut() const;

	public:
		Response* replyACK() const;
		Response* replyNACK() const;

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual Transaction& operator=(const Transaction& m);
		virtual bool operator==(const Transaction &other) const;
		virtual bool operator!=(const Transaction &other) const	{ return !(*this == other);  }
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	public:
		int64 id;
		long timestamp;
		long creator_id;
		short state;

		std::map<long, short> acks; // 0=unknown, 1=ACK, 2=NACK

		SharedMemoryDsm* parent; 
		friend class SharedMemory;

}; // class def

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

class TransactionAgentDeath : public Transaction
 {
	WOSH_SERIALIZABLE(wosh::TransactionAgentDeath)
	WOSH_COMPARE_RTTI(wosh::TransactionAgentDeath)

	public:
		TransactionAgentDeath( SharedMemoryDsm* parent = NULL );
		TransactionAgentDeath( const TransactionAgentDeath& m )
			: Transaction(m), died_agent_id(m.died_agent_id) { }

		virtual ~TransactionAgentDeath() { }


/** @name Transaction Interface
 * @{
 ******************************************************************************/
	public:
		WRESULT precommit();
		WRESULT commit();
		WRESULT rollback();

		inline Transation_TYPE getType() const		{ return Transaction::TYPE_DEATH; }
		inline Transation_SCOPE getScope() const	{ return Transaction::SCOPE_AGENTS; }

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setDiedAgentID( long id )					{ this->died_agent_id = id; }

//@}
	public:
		TransactionAgentDeath& operator=(const TransactionAgentDeath& m);

	public:
		//std::string toString() const;

	protected:
		long died_agent_id;	///< the id of the died agent

}; // class def

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////










}; // namespace wosh

#endif //__WOSH_Core_SharedTransaction_H__
